#ifndef _B5M_CLEANUP_H_
#define _B5M_CLEANUP_H_

#include "common.h"
#include <list>

B5M_BEGIN_VERSIONED_NAMESPACE_DECL
/**
 * @class B5M_Cleanup
 *
 * @brief Base class for objects that are cleaned by B5M_Object_Manager.
 */
class B5M_Export B5M_Cleanup
{
public:
  /// No-op constructor.
  B5M_Cleanup (void){};

  /// Destructor.
  virtual ~B5M_Cleanup (void){};

  /// Cleanup method that, by default, simply deletes itself.
  virtual void cleanup (void *param = 0)
  {
	  delete this;
  }
};

/// Adapter for cleanup, used by ACE_Object_Manager.
extern "C" B5M_Export void B5M_CLEANUP_DESTROYER_NAME (B5M_Cleanup *, void *param = 0);
/**
 * @class B5M_Cleanup_Adapter
 *
 * @brief Adapter for B5M_Cleanup objects that allows them to be readily
 * managed by the B5M_Object_Manager.
 *
 * This template class adapts an object of any type to be an
 * B5M_Cleanup object.  The object can then be destroyed
 * type-safely by the B5M_Object_Manager.  This class is
 * typically used to replace a cast; but, it's a bit cleaner and
 * allows insertion of, say, run-time type identification
 * internally if desired.
 */
template <class TYPE>
class B5M_Cleanup_Adapter : public B5M_Cleanup
{
public:
  /// Default constructor.
  B5M_Cleanup_Adapter (void){};

  /// Virtual destructor, needed by some compilers for vtable placement.
  virtual ~B5M_Cleanup_Adapter (void){};

  /// Accessor for contained object.
  TYPE &object (void) { return this->object_;};

private:
	B5M_Cleanup_Adapter (const B5M_Cleanup_Adapter<TYPE> &);
	void operator= (const B5M_Cleanup_Adapter<TYPE> &);
  /// Contained object.
  TYPE object_;
};

 typedef void (*B5M_CLEANUP_FUNC)(void *object, void *param);


// 
/**
 * @class B5M_Cleanup_Info_Node
 *
 * @brief For maintaining a list of ACE_Cleanup_Info items.
 *
 * For internal use by ACE_Object_Manager.
 */
 class B5M_Cleanup_Info_Node 
 {
 public:
	 B5M_Cleanup_Info_Node (void): object_ (0),
		 cleanup_hook_ (0),
		 param_ (0),
		 name_ (0)
	 { }

	 B5M_Cleanup_Info_Node (void *object,
		 B5M_CLEANUP_FUNC cleanup_hook,
		 void *param,
		 const char *name) : object_ (object),
		 cleanup_hook_ (cleanup_hook),
		 param_ (param),
		 name_ (name ? _strdup (name) : 0)
	 { }

	 ~B5M_Cleanup_Info_Node (void)
	 {
		 if (this->name_)
			 free ((void *) name_);
	 }

	 /// Equality operator.
	 bool operator== (const B5M_Cleanup_Info_Node &o) const  
	 {
		 return o.object_ == this->object_
			 && o.cleanup_hook_ == this->cleanup_hook_
			 && o.param_ == this->param_;
	 }

	 /// Inequality operator.
	 bool operator!= (const B5M_Cleanup_Info_Node &o) const{return !(*this == o);}

	 inline void* object(void){return this->object_;}

	 inline B5M_CLEANUP_FUNC cleanup_hook (void){	return this->cleanup_hook_;}

	 inline  void *param (void){return this->param_;}

 private:
	 /// Point to object that gets passed into the <cleanup_hook_>.
	 void *object_;

	 /// Cleanup hook that gets called back.
	 B5M_CLEANUP_FUNC cleanup_hook_;

	 /// Parameter passed to the <cleanup_hook_>.
	 void *param_;

	 /// Name of the cleanup object
	 const char *name_;
 };
// 
// 
/**
 * @class B5M_Exit_Info
 *
 * @brief Hold Object Manager cleanup (exit) information.
 *
 * @internal
 *
 * For internal use by the B5M library, only.
 */

class B5M_Export B5M_Exit_Info
{
public:
	typedef std::list<B5M_Cleanup_Info_Node*>::iterator NodeIter;

  /// Default constructor.
	B5M_Exit_Info (void){};

  /// Destructor.
  ~ B5M_Exit_Info (void){};

  /// Use to register a cleanup hook.
  int at_exit_i (void *object, B5M_CLEANUP_FUNC cleanup_hook, void *param, const char* name = 0)
  {
	// Return -1 and sets errno if unable to allocate storage.  Enqueue
	// at the head and dequeue from the head to get LIFO ordering.
	B5M_Cleanup_Info_Node *new_node = 0;

	B5M_NEW_RETURN (new_node,
		B5M_Cleanup_Info_Node (object, cleanup_hook, param, name),
		-1);

	registered_objects_.push_front (new_node);

	return 0;
  }

  /// Look for a registered cleanup hook object.  Returns true if already
  /// registered, false if not.
  bool find (void *object)
  {

	  for (NodeIter iter = registered_objects_.begin();
		  iter != registered_objects_.end();
		  iter++)
	  {
		  if ((*iter)->object () == object)
		  {
			  // The object has already been registered.
			  return true;
		  }
	  }

	  return false;
  }

  /// Remove a registered cleanup hook object.  Returns true if removed
  /// false if not.
  bool remove (void *object)
  {
	  B5M_Cleanup_Info_Node *node = 0;
	  for (NodeIter iter = registered_objects_.begin ();
		  iter != registered_objects_.end();
		  iter++)
	  {
		  if ((*iter)->object () == object)
		  {
			  node = *iter;
			  break;
		  }
	  }

	  if (node)
	  {
		  registered_objects_.remove(node);
		  delete node;
		  return true;
	  }
	  return false;
  }

  /// Call all registered cleanup hooks, in reverse order of
  /// registration.
  void call_hooks ()
  {
	  // Call all registered cleanup hooks, in reverse order of
	  // registration.
	  for (NodeIter iter = registered_objects_.begin ();
		  iter != registered_objects_.end();
		  iter++)
	  {
		  if ((*iter)->cleanup_hook () == reinterpret_cast<B5M_CLEANUP_FUNC> (B5M_CLEANUP_DESTROYER_NAME))
		  {
			  // The object is an ACE_Cleanup.
			  B5M_CLEANUP_DESTROYER_NAME (reinterpret_cast<B5M_Cleanup *> ((*iter)->object ()),(*iter)->param ());
		  }
		  else
		  {
			  (*(*iter)->cleanup_hook ()) ((*iter)->object (), (*iter)->param ());
		  }
		  delete *iter;
	  }
  }
private:
  /**
   * Keeps track of all registered objects.
   */
	std::list<B5M_Cleanup_Info_Node*> registered_objects_;
};

B5M_END_VERSIONED_NAMESPACE_DECL

#endif